﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Rvz.Game.Main.Entities.Zombies;
using Rvz.Game.Main.Rules.Waves;

namespace Rvz.Game.Main.State
{
    public class WaveState
    {
        public WaveState(IWaveLevel waveLevel)
        {
            WaveLevel = waveLevel;
        }

        public IWaveLevel WaveLevel { get; set; }

        private readonly ICollection<Zombie> _activeZombies = new Collection<Zombie>();
        public IEnumerable<Zombie> ActiveZombies
        {
            get { return _activeZombies; }
        }

        public void AddZombie(Zombie zombie)
        {
            _activeZombies.Add(zombie);
        }

        private readonly ICollection<Zombie> _fraggedZombies = new Collection<Zombie>();
        public IEnumerable<Zombie> FraggedZombies
        {
            get { return _fraggedZombies; }
        }

        public int TotalZombiesSpawned()
        {
            return ActiveZombies.Count() + FraggedZombies.Count();
        }

        public void FragZombie(Zombie zombie)
        {
            zombie.Destroy(); //TODO: Might need something to allow the finishing of the animation here before it's technically destroyed
            _activeZombies.Remove(zombie);
            _fraggedZombies.Add(zombie);
            zombie.IsActive = false;
        }

        public int GetZombieSpawnCount()
        {
            var activeCount = ActiveZombies.Count();
            var isPlayCountMaxed = TotalZombiesSpawned() >= WaveLevel.TotalZombiesOnLevel;
            var isScreenCountMaxed = activeCount >= WaveLevel.MaxZombiesOnScreen;
            if (isPlayCountMaxed || isScreenCountMaxed)
            { return 0; }

            var idealScreenSpawn = WaveLevel.MaxZombiesOnScreen - activeCount;
            var limitedSpawn = Math.Min(RemainingZombies(), idealScreenSpawn);
            return limitedSpawn;
        }

        public int RemainingZombies()
        {
            return WaveLevel.TotalZombiesOnLevel - TotalZombiesSpawned();
        }

        public bool IsWaveComplete()
        {
            return FraggedZombies.Count() >= WaveLevel.TotalZombiesOnLevel;
        }

        public WaveState NextWave()
        {
            Destroy();
            return new WaveState(WaveLevel.TransitionToNextLevel());
        }

        public void Destroy()
        {
            foreach (var activeZ in _activeZombies.ToArray())
            {
                activeZ.Destroy();
                _activeZombies.Remove(activeZ);
            }

            foreach (var fraggedZ in _fraggedZombies.ToArray())
            {
                fraggedZ.Destroy();
                _fraggedZombies.Remove(fraggedZ);
            }
        }
    }
}
